/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.meego.common.io.image;

import com.meego.common.config.Config;
import com.meego.common.log.GA;
import com.meego.common.util.StringUtils;
import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.RasterFormatException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 *
 * @author TueHM
 */
public class ImageProcess {

    private static List<String> modules;
    private static Map<String, List<String>> sizes;

    static {
        modules = new ArrayList<String>();
        sizes = new HashMap<String, List<String>>();
        Map<String, String> rewriteMap = Config.getMapConfig("meego.image.resize");
        Iterator<Map.Entry<String, String>> resize = rewriteMap.entrySet().iterator();
        while (resize.hasNext()) {
            Map.Entry<String, String> pairs = resize.next();
            String key = pairs.getKey();
            String value = pairs.getValue();
            if (key.contains(".")) {
                continue;
            }
            modules.add(key);
            sizes.put(key, StringUtils.toList(value, ","));
        }
    }

    public static boolean isSupportModule(String module) {
        return modules.contains(module);
    }

    public static BufferedImage resizeImage(BufferedImage originalImage, int type, int imgWidth, int imgHeight) {
        BufferedImage resizedImage = new BufferedImage(imgWidth, imgHeight, type);
        Graphics2D g = resizedImage.createGraphics();
        g.drawImage(originalImage, 0, 0, imgWidth, imgHeight, null);
        g.dispose();

        return resizedImage;
    }

    public static BufferedImage resizeImageWithHint(BufferedImage originalImage, int type, int imgWidth, int imgHeight) {

        BufferedImage resizedImage = new BufferedImage(imgWidth, imgHeight, type);
        Graphics2D g = resizedImage.createGraphics();
        g.drawImage(originalImage, 0, 0, imgWidth, imgHeight, null);
        g.dispose();
        g.setComposite(AlphaComposite.Src);

        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        return resizedImage;
    }

    public static BufferedImage cropImage(BufferedImage img, int cropWidth, int cropHeight, int cropStartX, int cropStartY) throws Exception {
        BufferedImage clipped;
        Dimension size = new Dimension(cropWidth, cropHeight);

        Rectangle clip = createClip(img, size, cropStartX, cropStartY);

        try {
            int w = clip.width;
            int h = clip.height;

            clipped = img.getSubimage(clip.x, clip.y, w, h);

        } catch (RasterFormatException rfe) {
            GA.service.error("Can not crop image.", rfe);
            return null;
        }
        return clipped;
    }

    /**
     * This method crops an original image to the crop parameters provided.
     * If the crop rectangle lies outside the rectangle (even if partially), adjusts the rectangle to be included within
     * the image area.
     * @param img = Original Image To Be Cropped
     * @param size = Crop area rectangle
     * @param clipX = Starting X-position of crop area rectangle
     * @param clipY = Strating Y-position of crop area rectangle
     * @throws Exception
     */
    private static Rectangle createClip(BufferedImage img, Dimension size, int clipX, int clipY) throws Exception {
        /**
         * Some times clip area might lie outside the original image, fully or partially. In such cases, this program
         * will adjust the crop area to fit within the original image.
         * isClipAreaAdjusted flas is usded to denote if there was any adjustment made.
         */
        Rectangle clip;
        boolean isClipAreaAdjusted = false;

        //Checking for negative X Co-ordinate*
        if (clipX < 0) {
            clipX = 0;
            isClipAreaAdjusted = true;
        }
        //Checking for negative Y Co-ordinate*
        if (clipY < 0) {
            clipY = 0;
            isClipAreaAdjusted = true;
        }

        //Checking if the clip area lies outside the rectangle*
        if ((size.width + clipX) <= img.getWidth() && (size.height + clipY) <= img.getHeight()) {

            //Setting up a clip rectangle when clip area lies within the image.
            clip = new Rectangle(size);
            clip.x = clipX;
            clip.y = clipY;
        } else {

            //Checking if the width of the clip area lies outside the image. If so, making the image width boundary as the clip width.
            if ((size.width + clipX) > img.getWidth()) {
                size.width = img.getWidth() - clipX;
            }

            //Checking if the height of the clip area lies outside the image. If so, making the image height boundary as the clip height.
            if ((size.height + clipY) > img.getHeight()) {
                size.height = img.getHeight() - clipY;
            }

            //Setting up the clip are based on our clip area size adjustment*
            clip = new Rectangle(size);
            clip.x = clipX;
            clip.y = clipY;

            isClipAreaAdjusted = true;

        }
        if (isClipAreaAdjusted) {
            GA.service.info("Crop Area Lied Outside The Image. Adjusted The Clip Rectangle");
        }
        return clip;
    }
}
